package com.example.dayu521.sg_oss.service.impl;

import com.example.dayu521.sg_oss.conf.RedisC;
import com.example.dayu521.sg_oss.domain.NumSplit;
import com.example.dayu521.sg_oss.service.OrderNumSource;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.hash.Jackson2HashMapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

//todo RedisSourceImpl
@Slf4j
@Service
@ConditionalOnProperty(prefix = "sg.num",name = "backend",havingValue = "redis")
public class RedisSourceImpl implements OrderNumSource {

    @Autowired
    private Map<Long,RedisTemplate<String,Object>> redisTemplateMap;

    private final ArrayList<Long> ia=new ArrayList<>();

    @PostConstruct
    public void init(){
        redisTemplateMap.forEach((k,v)->{
            ia.add(k);
        });
    }


    @Override
    public Long get_random_node() {
        return ia.get(new Random().nextInt(ia.size()));
    }

    @Override
    public void save_to(Long node_index, Map<String, ?> multi_keys) {
        assert node_index<redisTemplateMap.size();
        redisTemplateMap.get(node_index).opsForValue().multiSet(multi_keys);
    }

    @Override
    public <T> void save_to(Long node_index, String key, T obj,long version) {
        //原子比较插入
        redisTemplateMap.get(node_index).execute(RedisScript.of("""
                local current_version = redis.call('GET', KEYS[2])
                if current_version > ARGV[2]
                  then return false
                end
                redis.call('SET', KEYS[1], ARGV[1])
                redis.call('SET', KEYS[2], ARGV[2])
                return true
                """,Boolean.class), List.of(key,key+":version"),obj,version);
//        redisTemplateMap.get(node_index).opsForValue().set(key,obj);
    }

    @Override
    public <T> boolean save_not_exist(Long node_index, String key, T obj) {
        return redisTemplateMap.get(node_index).opsForValue().setIfAbsent(key,obj);
    }

    @Override
    public boolean save_not_exist(Long node_index, Map<String, ?> multi_keys) {
        return redisTemplateMap.get(node_index).opsForValue().multiSetIfAbsent(multi_keys);
    }

    @Override
    public <T> T pull_from(Long node_index, String key) {
        return (T)redisTemplateMap.get(node_index).opsForValue().get(key);
    }

    @Override
    public Long get_next_long(Long node_index, String key) {
        return redisTemplateMap.get(node_index).opsForValue().decrement(key);
    }
}
